﻿using System;

namespace UnityEngine.UI
{
	[AddComponentMenu("Layout/Content Size Fitter Offset", 141)]
	[ExecuteInEditMode]
	[RequireComponent(typeof(RectTransform))]
	public class ContentSizeFitterOffset : ContentSizeFitter, ILayoutElement
	{

		[SerializeField]
		protected Vector2 m_Offset = Vector2.one;
		public Vector2 Offset { get { return m_Offset; } set { if (SetPropertyUtility.SetStruct(ref m_Offset, value)) SetDirty(); } }
		[NonSerialized]
		protected RectTransform m_Rect;
		[SerializeField]
		private bool mIncludeChild = true;                      //
		[SerializeField]
		protected Vector2 m_MinSize = Vector2.one;
		public Vector2 MinSize { get { return m_MinSize; } set { if (SetPropertyUtility.SetStruct(ref m_MinSize, value)) SetDirty(); } }

		[SerializeField]
		protected Vector2 m_MaxSize = Vector2.one * -1f;
		public Vector2 MaxSize { get { return m_MaxSize; } set { if (SetPropertyUtility.SetStruct(ref m_MaxSize, value)) SetDirty(); } }

		private float mMinWidth;                      //
		private float mPrefferWidth;                      //
		private float mFlexibleWidth;                      //

		private float mMinHeght;                      //
		private float mPrefferHeght;                      //
		private float mFlexibleHeght;                      //

		protected RectTransform rectTransform
		{
			get
			{
				if ((UnityEngine.Object)this.m_Rect == (UnityEngine.Object)null)
					this.m_Rect = this.GetComponent<RectTransform>();
				return this.m_Rect;
			}
		}

		public float minWidth
		{
			get
			{
				return mMinWidth;// ;
			}
		}

		public float preferredWidth
		{
			get { return mPrefferWidth; }
		}

		public float flexibleWidth
		{
			get { return mFlexibleWidth; }
		}

		public float minHeight
		{
			get { return mMinHeght; }
		}

		public float preferredHeight
		{
			get { return mPrefferHeght; }
		}

		public float flexibleHeight
		{
			get
			{
				return mFlexibleHeght;
			}
		}

		public int layoutPriority
		{
			get
			{
				return 0;
			}
		}

		protected void HandleSelfFittingAlongAxisOffset(int axis)
		{
			//this.Call("HandleSelfFittingAlongAxis", axis);
			var fitting = (axis == 0 ? horizontalFit : verticalFit);
			switch (fitting)
			{
				case FitMode.Unconstrained:
					return;
				// Set size to min or preferred size
				case FitMode.MinSize:
					rectTransform.SetSizeWithCurrentAnchors((RectTransform.Axis)axis,GetMinSize(axis));
					break;
				default:
					rectTransform.SetSizeWithCurrentAnchors((RectTransform.Axis)axis, GetAxisPreferValue(axis));
					break;
			}
		}

		protected float GetMinSize(int axis)
		{
			return LayoutUtilityExt.GetMinSize(m_Rect, axis,this); // + Offset[axis];
		}

		protected override void OnEnable()
		{
			base.OnEnable();
#if false
			rectTransform.ForEachChild(it =>
				{
					var transf = it.GetComponent<Graphic>();
					if (transf)
					{
						transf.RegisterDirtyLayoutCallback(UpdateLayout);
					}
					//var tras = it as RectTransform;
				});
#endif
		}

		public void UpdateLayout()
		{
			HandleSelfFittingAlongAxisOffset(0);
			HandleSelfFittingAlongAxisOffset(1);

		}


		protected override void OnDisable()
		{
			base.OnDisable();
#if false
			rectTransform.ForEachChild(it =>
			{
				var transf = it.GetComponent<Graphic>();
				if (transf)
				{
					transf.UnregisterDirtyLayoutCallback(UpdateLayout);
				}
				//var tras = it as RectTransform;
			});
#endif
		}

		public float GetAxisPreferValue(int axis)
		{
			var v = LayoutUtilityExt.GetPreferredSize(m_Rect, axis,this);
			v = Mathf.Max(MinSize[axis], v);
			if (mIncludeChild)
			{
				m_Rect.ForEachChild(it =>
				{
					var size = LayoutUtility.GetPreferredSize(it as RectTransform, axis);
					v = Mathf.Max(size, v);
				});

			}

			v += Offset[axis];

			var max = MaxSize[axis];
			if (max > 0)
			{
				v = Mathf.Min(v, max);
			}
			//Debug.LogFormat("{0} axis :{1}",axis,v);
			return v;
		}

		public override void SetLayoutHorizontal()
		{
			base.SetLayoutHorizontal();
			HandleSelfFittingAlongAxisOffset(0);
		}

		public override void SetLayoutVertical()
		{
			base.SetLayoutVertical();
			HandleSelfFittingAlongAxisOffset(1);
		}

		public void CalculateLayoutInputHorizontal()
		{
			//throw new NotImplementedException();
			mMinWidth = GetMinSize(0);
			mPrefferWidth = GetAxisPreferValue(0);
			mFlexibleWidth = LayoutUtility.GetFlexibleWidth(rectTransform);
		}

		public void CalculateLayoutInputVertical()
		{
			//throw new NotImplementedException();
			mMinHeght = GetMinSize(1);
			mPrefferHeght = GetAxisPreferValue(1);
			mFlexibleHeght = LayoutUtility.GetFlexibleHeight(rectTransform);
		}
	}
}
